-- NOTE:
-- All local functions and values get recalculated on script reload.
-- All global functions and values get recalculated on script reload UNLESS it is wrapped like this:
-- value = value or {...}
-- Try to use local functions and values everywhere unless it must be accessed from Monkey or must be
-- maintained between script loads.
-- This is mainly to reduce the number of global lookups.

local oldprint = print
local olderror = error

local print = function(...)
  Print(...)
  oldprint(...)
end

local error = function(...)
  local message = ...
  Print(message)
  olderror(...)
end

print('Loading script!')

function CreateScreen(name)
  return {
    name = name,
    OnUpdate = function (delta) end,
    OnRender = function (delta) end,
    OnLoad = function () end,
    OnUnload = function () end
  }
end

function CreateGame()
  return {
    images = {},
    sounds = {},
    state = {
      currentscreen = 'title',
      targetscreen = '',
      fadeoutremaining = 0,
      fadeinremaining = 0,
      fadetime = 500,
      level = {},
      units = {},
      --
      playerhp = 10,
      playermaxhp = 10,
      hasmedpack = false,
      score = 0,
      clip = 15,
      maxclip = 15,
      levelnum = 0,
      zombiehealth = 0
    },
    screens = {
      intro = CreateScreen('intro'),
      title = CreateScreen('title'),
      game = CreateScreen('game'),
      score = CreateScreen('score'),
      gameover = CreateScreen('gameover'),
      credits = CreateScreen('credits')
    }
  }
end

game = game or CreateGame()

-------------------------- LOCAL VALUES --------------------------
local game = game
local images = game.images
local sounds = game.sounds
local state = game.state
local screens = game.screens

local SCREEN_WIDTH = DeviceWidth()
local SCREEN_HEIGHT = DeviceHeight()

-------------------------- UTILITIES --------------------------
local function tablecount(tbl)
  local count = 0
  for _,_ in pairs(tbl) do count = count + 1 end
  return count
end

local function loadimg(filename)
  return LoadImage('graphics/'..filename) or print("Couldn't load '"..filename.."'")
end

local function loadanimimg(filename, framecount)
  return LoadImage('graphics/'..filename, framecount) or print("Couldn't load '"..filename.."'")
end

local function loadsnd(filename)
  return LoadSound('sounds/'..filename) or print("Couldn't load '"..filename.."'")
end

-------------------------- RESOURCES --------------------------

local function LoadImages()
  print('Loading images...')
  local rv = {
    bullet = loadimg('bullet.png'),
    flashlight = loadimg('flashlight.png'),
    font = loadimg('font.png'),
    gui = loadimg('gui.png'),
    hp = loadanimimg('hp.png', 2),
    medpack = loadimg('medpack.png'),
    tileset = loadimg('tileset.png'),
    title = loadimg('title.png'),
    units = loadimg('units.png')
  }
  print(tablecount(images)..' images loaded.')
  return rv
end

local function LoadSounds()
  print('Loading sounds...')
  rv = {
    claw1 = loadsnd('claw1.wav'),
    claw2 = loadsnd('claw2.wav'),
    gun = loadsnd('gun.wav'),
    idle1 = loadsnd('idle1.wav'),
    idle2 = loadsnd('idle2.wav'),
    reload = loadsnd('reload.wav'),
    scream1 = loadsnd('scream1.wav'),
    scream2 = loadsnd('scream2.wav'),
    sight1 = loadsnd('sight1.wav'),
    sight2 = loadsnd('sight2.wav')
  }
  print(tablecount(sounds)..' sounds loaded.')
  return rv
end

local function LoadResources()
  images = LoadImages()
  game.images = images
  sounds = LoadSounds()
  game.sounds = sounds
end

-------------------------- LOCAL FUNCS --------------------------

local function CreateRoom(...)
  local cells = {...}
  return {
    fade = 0,
    visible = false,
    cells = cells
  }
end

local function CreateCell(id, x, y)
  return {
    hasmedpack = false,
    hasexit = false,
    index = 0,
    walls = {false, false, false, false}
  }
end

local function FlashText(text, x, y, freq, alignX, alignY)
  if Millisecs() % freq*2 < freq then
    DrawText(text, x, y, alignX or 0, alignY or 0)
  end
end

local function FadeToScreen(name)
  state.targetscreen = name
  state.fadeoutremaining = state.fadetime
  state.fadeinremaining = state.fadetime
end

local function InitGame(levelnum)
  state.score = 0
  state.hasmedpack = false
  state.bullets = {}
  InitLevel(levelnum)
end

local function InitLevel(levelnum)
  state.clip = 15
  state.levelnum = levelnum
  GenerateMap(levelnum, 6, 6)
end

local function GenerateMap(levelnum, cellwidth, cellheight)
  --[[local maxcells = math.min(16, levelnum+1)
  local mapsize = maxcells*(cellwidth+1)+1
  local grid = {}, rooms = {}, tiles = {}
  state.rooms = rooms]]
end

-------------------------- CALLED BY MONKEY --------------------------

function Create()
  LoadResources()
  screen = 'title'
end

function Update(delta)


  if state.fadeoutremaining > 0 then
    state.fadeoutremaining = state.fadeoutremaining - delta
    if state.fadeoutremaining <= 0 then
      state.fadeinremaining = state.fadeinremaining + state.fadeoutremaining
      state.fadeoutremaining = 0
      screens[state.currentscreen]:OnUnload()
      state.currentscreen = state.targetscreen
      state.targetscreen = ''
      screens[state.currentscreen]:OnLoad()
    end
  end
  if state.fadeoutremaining <= 0 and state.fadeinremaining > 0 then
    state.fadeinremaining = state.fadeinremaining - delta
    if state.fadeinremaining < 0 then
      state.fadeinremaining = 0
    end
  end

  if state.fadeoutremaining > 0 or state.fadeinremaining > 0 then return end

  if KeyHit(KEY_F1) then
    print('reloading resources')
    LoadResources()
  end

  if KeyHit(KEY_F2) then
    print('recreating game')
    _G.game = CreateGame()
    game = _G.game
    LoadResources()
  end

  if screens[state.currentscreen] then
    screens[state.currentscreen]:OnUpdate(delta)
  end
end

function Render(delta)
  SetColor(255, 255, 255)
  if screens[state.currentscreen] then
    screens[state.currentscreen]:OnRender(delta)
  end
  if state.fadeoutremaining > 0 then
    SetAlpha(1-(state.fadeoutremaining/state.fadetime))
    SetColor(0, 0, 0)
    DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
  elseif state.fadeinremaining > 0 then
    SetAlpha(state.fadeinremaining/state.fadetime)
    SetColor(0, 0, 0)
    DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
  end
end

-------------------------- SCREENS --------------------------
-- title screen
function screens.title:OnUpdate(delta)
  if KeyHit(KEY_ESCAPE) then
    print('quitting')
    Quit()
  elseif KeyHit(KEY_SPACE) then
    FadeToScreen('game')
  elseif KeyHit(KEY_C) then
    FadeToScreen('credits')
  end
end

function screens.title:OnRender(delta)
  SetColor(255, 255, 255)
  if images.title then DrawImage(images.title, SCREEN_WIDTH/2-280, 0, 0, 2, 2) end

  DrawText('W,A,S,D: Move',                           SCREEN_WIDTH/2, 290, 0.5, 0) -- 90
  DrawText('Mouse: Aim flashlight, click to fire',    SCREEN_WIDTH/2, 310, 0.5, 0) -- 251
  DrawText('Shift: Sprint (can\'t fire)',             SCREEN_WIDTH/2, 330, 0.5, 0) -- 179
  DrawText('R: Reload  F: First Aid  E: Use stairs',  SCREEN_WIDTH/2, 350, 0.5, 0) -- 264
  FlashText('Press space to play!',                   SCREEN_WIDTH/2, 390, 500, 0.5, 0) -- 136

  SetColor(128, 128, 128)
  DrawText('C: Credits', 10, 460)
end

-- game screen
function screens.game:OnUpdate(delta)
  -- do the title confirmation
  if self.showconfirmtitle then
    if KeyHit(KEY_ESCAPE) or KeyHit(KEY_N) then
      self.showconfirmtitle = false
    elseif KeyHit(KEY_Y) then
      FadeToScreen('title')
    end
    return
  elseif KeyHit(KEY_ESCAPE) then
    self.showconfirmtitle = true
    return
  end

  if MouseHit() and sounds.gun then
    print('playing fire')
    PlaySound(sounds.gun)
  end
  if KeyHit(KEY_R) and sounds.reload then
    print('playing reload')
    PlaySound(sounds.reload)
  end
end

function screens.game:OnRender(delta)
  SetColor(255, 255, 255)

  -- draw gui labels
  if images.gui then DrawImage(images.gui, 16, 16) end

  -- draw health bar
  if not images.hp then
    print('images.hp is nil!')
  else
    for i = 0,state.playermaxhp-1 do
      if state.playerhp > i then
        DrawImage(images.hp, 53+i*3, 19, 0)
      else
        DrawImage(images.hp, 53+i*3, 19, 1)
      end
    end
  end

  -- draw clip
  if not images.bullet then
    print('images.bullet is nil!')
  else
    for i = 0,state.clip do
      DrawImage(images.bullet, 52+i*3, 31)
    end
  end

  if self.showconfirmtitle then
    SetColor(0, 0, 0)
    SetAlpha(0.5)
    DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
    SetColor(255, 255, 255)
    SetAlpha(1)
    DrawText('Return to title screen? Y/N', SCREEN_WIDTH/2, SCREEN_HEIGHT/2, 0.5, 0.5)
  end
end

function screens.game:OnLoad()
  self.showconfirmtitle = false
end

-- credits screen
function screens.credits:OnUpdate(delta)
  if KeyHit(KEY_ESCAPE) then
    FadeToScreen('title')
  end
end

function screens.credits:OnRender(delta)
end

print('Script loaded!')
